import java.applet.*;
import java.awt.*;
import java.util.Random;
import java.util.Vector;


public class evolution extends Applet
{
	static final int FRAMEHEIGHT = 650;
	static final int FRAMEWIDTH = 700;
	static final int RECTHEIGHT = 200;
	static final int RECTWIDTH = 100;
	static final int ECART = 30;
	static final int BASE  = 30;
	static final int TEXTHIGH = 30;
	static final int OFFSET_TOP = 70;

	static int iTop  = 0;
	static int iLeft = 10;

	static int iTop1 = OFFSET_TOP;
	static int iTop2 = iTop1 + RECTHEIGHT + ECART;
	static int iTop3 = iTop1 + 2 * (RECTHEIGHT + ECART);

	static int iOnecol = RECTWIDTH + ECART;
	static int iOneline = RECTHEIGHT + ECART;
	static int iLeftParent = iLeft+(4*iOnecol) + 20;

	static final int NBMORPHS = 8;
	private int selected[];
	private int nbSelected;
	private boolean bMigration;
	private int nGeneration;
	private genome Genome[];
	private morph Morph[];
	private Checkbox cb[];
	private boolean bDisplayTxtGene = false;
	private TextField txtGene[];

	private morph Parent[];
	private Checkbox cbParent[];
	private TextField txtParentGene[];
	private String[] sParent = { "Father", "Mother" } ;
	static final int FATHER = 100;
	static final int MOTHER = 101;

	private Button btnGo;
	private Button btnMigrate;
	private Button btnShowGenome;
	private Label lblMutation;
	private Label lblTranscription;
	private List lstMutation;
	private List lstTranscription;
	private List lstBackColor;
	private List lstForeColor;

	private Color frameColor;
	private Color backGround;
	private Color foreGround;
	private String[] sColor = {	"black", "blue", "cyan","darkgray",
								"gray", "green", "lightgray","magenta",
								"orange", "pink", "red", "white", "yellow"};

	static final int DEF_FRAME_COLOR = 6; // lightGray
	static final int DEF_BACK_COLOR = 11; // white
	static final int DEF_FORE_COLOR = 0; // black


	// ***************** default parameters
	private int MaxSeverity = 3;
	private int TypeTranscription = 1;
	private int NbCrossover = 3;

	private Random rnd;

	public evolution()
	{
		rnd = new Random();  // try 2, 4
		nGeneration = 0;
		bMigration = false;
		Genome = new genome[NBMORPHS];
		Morph = new morph[NBMORPHS];
		selected = new int[2];
		selected[0] = 0;
		selected[1] = 0;
		nbSelected = 0;

		Parent = new morph[2];

		frameColor = new Color(0); // lightGray = (192, 192, 192);
		backGround = new Color(0);
		foreGround = new Color(0);
		frameColor = fixColor( DEF_FRAME_COLOR);
		backGround = fixColor(DEF_BACK_COLOR);
		foreGround = fixColor(DEF_FORE_COLOR);

		Genese();
	}

	private void Genese()
	{
		for (int i = 0; i < NBMORPHS; i++)
		{
			Genome[i] = new genome( rnd );
			Morph[i] = new morph(Genome[i], TypeTranscription);
	    }
	}

	private void NewGenese()
	{
		Genese();
		resetCB();
		bMigration = true;
		repaint();
	}

	private void NewGeneration()
	{
		String sDNA0, sDNA1;

		nGeneration++;
		bMigration = false;
		zygote Zygote;
		morph father, mother;
		switch (selected[0])
		{
		case FATHER:father = Parent[0];sDNA0=txtParentGene[0].getText();break;
		case MOTHER:father = Parent[1];sDNA0=txtParentGene[1].getText();break;
		default: father = Morph[selected[0] - 1];
				 sDNA0=txtGene[selected[0] - 1].getText();break;
		}
		if (nbSelected > 1)	{
			switch (selected[1])
			{
			case FATHER:mother = Parent[0];sDNA1=txtParentGene[0].getText();break;
			case MOTHER:mother = Parent[1];sDNA1=txtParentGene[1].getText();break;
			default: mother = Morph[selected[1] - 1];
					 sDNA1=txtGene[selected[1] - 1].getText();break;
			}
		} else {
			mother = father;
			sDNA1 = sDNA0;
		}
		Parent[0] = new morph (sDNA0, TypeTranscription);
		if  (Parent[0].Isvalid()  == false) {
			Parent[0] = new morph (father.Genome, TypeTranscription); }
		Parent[1] = new morph (sDNA1, TypeTranscription);
		if (Parent[1].Isvalid() == false) {
			Parent[1] = new morph (mother.Genome, TypeTranscription);  }
		for (int i = 0; i < NBMORPHS; i++)
		{
			Zygote = new zygote(Parent[0].Genome, Parent[1].Genome);
			Zygote.crossing_over(rnd, NbCrossover);
			Morph[i] = new morph(Zygote.getChild(rnd), TypeTranscription);
			Morph[i].mutate(MaxSeverity, rnd);
	    }
		resetCB();
	}

	public String getAppletInfo()
	{
		return "Name: Morphs\r\n" +	"Author: Alain Gogniat\r\n" + "Date: November 17, 1997";
	}

	public void init()
	{
		DrawFrames();
		dispOperation();
		resetCB();
	}

	private void DrawFrames()
	{
		setLayout(null);
		resize(FRAMEWIDTH, FRAMEHEIGHT);

		// ************ label Mutation
		lblMutation = new Label();
		add(lblMutation);
		lblMutation.setBackground(frameColor);
		lblMutation.reshape(iLeft+2*iOnecol, iTop, 200,20);

		// ************ label Transcription
		lblTranscription = new Label();
		add(lblTranscription);
		lblTranscription.setBackground(frameColor);
		lblTranscription.reshape(iLeft+2*iOnecol, iTop + 20, 200,20);

		// ************ button GO (REPRODUCTION, CLONE, SELECT)
		btnGo = new Button("REPRODUCTION");
		add (btnGo);
		btnGo.reshape(iLeft, iTop + 45, iOnecol + RECTWIDTH, 20);

		//************ button MIGRATE
		btnMigrate = new Button("M I G R A T E");
		add (btnMigrate);
		btnMigrate.reshape(iLeft+2*iOnecol, iTop + 45, RECTWIDTH, 20);

		// ************ Show & Hide Genome
		btnShowGenome = new Button("Show Genome");
		add (btnShowGenome);
		btnShowGenome.reshape(iLeft+3*iOnecol, iTop + 45, RECTWIDTH, 20);

		// ************ Label Select Mutation
		Label lblSeverityList = new Label();
		lblSeverityList.setText("Mutations:");
		add(lblSeverityList);
		lblSeverityList.setBackground(frameColor);
		lblSeverityList.reshape(iLeft, iTop3, RECTWIDTH, 20);

		// ************ Select Severity of Mutation in List
		lstMutation = new List(4, false);
		lstMutation.addItem("None");
		lstMutation.addItem("Low");
		lstMutation.addItem("Medium");
		lstMutation.addItem("High");
		add(lstMutation);
		lstMutation.select(MaxSeverity);
		lstMutation.makeVisible(MaxSeverity);
		lstMutation.reshape(iLeft+RECTWIDTH , iTop3, RECTWIDTH, 50);

		// ************ Label Select Type of Transcription
		Label lblTranscriptionList = new Label();
		lblTranscriptionList.setText("Transcription:");
		lblTranscriptionList.setBackground(frameColor);
		add(lblTranscriptionList);
		lblTranscriptionList.reshape(iLeft+2*iOnecol, iTop3, RECTWIDTH, 20);

		// ************ Select Type of Transcription in List
		lstTranscription = new List(0, false);
		lstTranscription.addItem("random order");
		lstTranscription.addItem("forced order");
		add(lstTranscription);
		lstTranscription.select(TypeTranscription);
		lstTranscription.makeVisible(TypeTranscription);
		lstTranscription.reshape(iLeft+2*iOnecol+RECTWIDTH , iTop3, RECTWIDTH, 50);

		// ************ Label Select background color
		Label lblBckgnd = new Label();
		lblBckgnd.setText("Background");
		lblBckgnd.setBackground(frameColor);
		add(lblBckgnd);
		lblBckgnd.reshape(iLeft, iTop3+60, RECTWIDTH, 20);

		// ************ Label Select foreground color
		Label lblForegnd = new Label();
		lblForegnd.setText("Foreground");
		lblForegnd.setBackground(frameColor);
		add(lblForegnd);
		lblForegnd.reshape(iLeft+2*iOnecol, iTop3+60, RECTWIDTH, 20);

		// ************ Select Background 1 Foreground color
		lstBackColor = new List(0, false);
		lstForeColor = new List(0, false);
		for (int i=0; i < 13; i++)
		{
			lstBackColor.addItem(sColor[i]);
			lstForeColor.addItem(sColor[i]);
		}
		add(lstBackColor);
		lstBackColor.select(DEF_BACK_COLOR);
		lstBackColor.makeVisible(DEF_BACK_COLOR);
		lstBackColor.reshape(iLeft+RECTWIDTH , iTop3+60, RECTWIDTH, 50);
		add(lstForeColor);
		lstForeColor.select(DEF_FORE_COLOR);
		lstForeColor.reshape(iLeft+2*iOnecol+RECTWIDTH , iTop3+60, RECTWIDTH, 50);

		// ************ textfields to display genome
		txtGene = new TextField[NBMORPHS];
		txtParentGene = new TextField[2];

		// ************ checkboxes to select parents
		cb = new Checkbox[NBMORPHS];
		//LGene = new Label[NBMORPHS];
		cbParent = new Checkbox[2];

		// ************ Init textfields + checkboxes
		int No = 0;
		for (int line = 0; line < 2; line++)
		{
	/*		if (line == 0) {
				cbParent[line] = new Checkbox(FATHER);
				}
			else {
			  cbParent[line] = new Checkbox(MOTHER);
			}		  */
			cbParent[line] = new Checkbox(sParent[line]);
			add(cbParent[line]);
			cbParent[line].reshape(iLeftParent+ECART,
						      2 + iTop1 + RECTHEIGHT + line * iOneline,
						      60, 20);
			txtParentGene[line] = new TextField();
			add(txtParentGene[line]);
			txtParentGene[line].show(false);
			txtParentGene[line].reshape(iLeftParent,
						      2 + iTop1 + RECTHEIGHT + line * iOneline-TEXTHIGH,
						      RECTWIDTH, TEXTHIGH);

			for (int col = 0; col < NBMORPHS / 2; col++)
			{
				cb[No] = new Checkbox(""+(No+1));
				cb[No].setBackground(frameColor);
				add(cb[No]);
				cb[No].reshape( iLeft+col * iOnecol + ECART,
						      2 + iTop1 + RECTHEIGHT + line * iOneline,
						      40, 20);
				txtGene[No] = new TextField();
				add(txtGene[No]);
				txtGene[No].setEditable(false);
				txtGene[No].show(bDisplayTxtGene);
				txtGene[No].reshape( iLeft+col * iOnecol ,
						      2 + iTop1 + RECTHEIGHT + line * iOneline- TEXTHIGH,
						      RECTWIDTH, TEXTHIGH);
				No++;
			}
		}
		dispMutation();
		dispTranscription();
	}

	public void paint(Graphics g)
	{
//		frameColor = fixColor(4);
		g.setColor(frameColor);
		if (nGeneration == 0) {
			g.fillRect(0,0,FRAMEWIDTH, FRAMEHEIGHT);
			}
		g.draw3DRect(iLeft,iTop,2*RECTWIDTH + ECART, 40, true);
		Font f = getFont();
		g.setColor(Color.black);
		g.setFont(new Font("Helvetica", Font.BOLD, 24));
		g.drawString("GENERATION  "+nGeneration, iLeft+5,iTop+32);
		g.setFont(f);

		for (int line = 0; line < 2; line++) // First, draw the two parents
		{
			if (nGeneration != 0) {
			g.setColor(frameColor);
			g.draw3DRect(iLeftParent,
						iTop1 + line * iOneline,
						RECTWIDTH,
						RECTHEIGHT, false);
			g.setColor(backGround);
			g.fillRect( iLeftParent,
						iTop1 + line * iOneline,
						RECTWIDTH,
						RECTHEIGHT);
			g.setColor(foreGround);
			Parent[line].phenotype( g,
									iLeftParent + RECTWIDTH / 2 ,
									iTop1 + RECTHEIGHT - BASE + line * iOneline);
			txtParentGene[line].setText(Parent[line].toString());
			txtParentGene[line].show(bDisplayTxtGene);
			}
		}
		for (int line = 0; line < 2; line++) // Then, draw the eight children
		{
			for (int col = 0; col < NBMORPHS / 2; col++)
			{
			    g.setColor(frameColor);
			    g.draw3DRect(iLeft+ col * iOnecol,
							iTop1 + line * iOneline,
							RECTWIDTH,
							RECTHEIGHT, false);
				g.setColor(backGround);
				g.fillRect( iLeft + col * iOnecol,
							iTop1 + line * iOneline,
							RECTWIDTH,
							RECTHEIGHT);
			}
		}
		int j = 0;
		g.setColor(foreGround);
		for (int line = 0;  line < 2; line++)
		{
			for (int col = 0; col < NBMORPHS / 2; col++)
			{
				Morph[j].phenotype( g,iLeft + col * iOnecol + RECTWIDTH / 2,iTop1 + line * iOneline + RECTHEIGHT - BASE );
				txtGene[j].setText(Morph[j].toString());
				j++;
			}
		}
		bMigration = false;
		if (nGeneration != 0) {
		}
	}

	private Color fixColor ( int selection)
	{
		Color c = new Color(0);
		switch (selection)
		{
		case  0: c = Color.black ; break;
		case  1: c = Color.blue ; break;
		case  2: c = Color.cyan ; break;
		case  3: c = Color.darkGray ;break;
		case  4: c = Color.gray ; break;
		case  5: c = Color.green ;break;
		case  6: c = Color.lightGray ; break;
		case  7: c = Color.magenta ;	break;
		case  8: c = Color.orange ; break;
		case  9: c = Color.pink ; break;
		case 10: c = Color.red ; break;
		case 11: c = Color.white ; break;
		case 12: c = Color.yellow ;	break;
		}
		return c;
	}

	private void flipShowGenome()
	{
		bDisplayTxtGene = ! bDisplayTxtGene;
		if (bDisplayTxtGene) {
			btnShowGenome.setLabel("Hide Genome");
		} else {
			btnShowGenome.setLabel("Show Genome");
		}
		for (int i = 0; i < NBMORPHS; i++ ) {
			txtGene[i].show(bDisplayTxtGene);
		}
		if (nGeneration > 0 ) {
		txtParentGene[0].show(bDisplayTxtGene);
		txtParentGene[1].show(bDisplayTxtGene);
		}
	}

	private void resetCB()
	{
		selected[0] = 0;
		selected[1] = 0;
		nbSelected = 0;
		for (int i = 0; i < NBMORPHS; i++)
			cb[i].setState(false);
		cbParent[0].setState(false);
		cbParent[0].show(nGeneration != 0);
		cbParent[1].setState(false);
		cbParent[1].show(nGeneration != 0);
		dispOperation();
	}

	private void dispMutation()
	{
	   switch (MaxSeverity)
	   {
		case 0: lblMutation.setText("Mutation = none"); break;
		case 1: lblMutation.setText("Mutation = low"); ;break;
		case 2: lblMutation.setText("Mutation = medium");break;
		case 3: lblMutation.setText("Mutation = high");break;
	   }
	}

	private void dispTranscription()
	{
	   switch (TypeTranscription)
	   {
		case 0: lblTranscription.setText("Transcription = random order"); break;
		case 1: lblTranscription.setText("Transcription = forced order");break;
	   }
	   if (nGeneration != 0 ) {
		for (int i = 0; i < NBMORPHS; i++) {
			   Morph[i].reTranscript(TypeTranscription);
		}
		Parent[0].reTranscript(TypeTranscription);
		Parent[1].reTranscript(TypeTranscription);
	   }
	}

	private void dispOperation()
	{
	   switch (nbSelected)
	   {
	   case 0: btnGo.disable(); btnGo.setLabel("SELECT"); break;
	   case 1: btnGo.enable(); btnGo.setLabel("CLONE"); ;break;
	   case 2: btnGo.enable(); btnGo.setLabel("REPRODUCTION");break;
	   }
	}

	private void addSelected(String s)
	{
		Integer i;
		if (s == sParent[0])  {
			i = new Integer(FATHER);
		} else if (s == sParent[1]) {
			i = new Integer(MOTHER);
		}	else {
  		    i = new Integer(s);
		}
		if (nbSelected == 0) {
			selected[0] = i.intValue();
			nbSelected++;
		} else if (nbSelected == 1) {
			selected[1] = i.intValue();
			nbSelected++;
		} else if (nbSelected > 1) {
			if (selected[0] == FATHER) {
				cbParent[0].setState(false);
			} else if (selected[0] == MOTHER) {
				cbParent[1].setState(false);
			} else {
 				cb[selected[0]-1].setState(false);
			}
			selected[0] = selected[1];
			selected[1] = i.intValue();
		}
		dispOperation();
	}

	private void delSelected(String s)
	{
		Integer i;
		if (s == sParent[0])  {
			i = new Integer(FATHER);
		} else if (s == sParent[1]) {
			i = new Integer(MOTHER);
		}	else {
  		    i = new Integer(s);
		}
		if (selected[0] == i.intValue()) {
			selected[0] = selected[1];
			nbSelected --;
		} else if (selected[1] == i.intValue()) {
			if (i.intValue() == FATHER) {
				cbParent[0].setState(false);
			} else if (i.intValue() == MOTHER) {
				cbParent[0].setState(false);
			} else {
				cb[selected[0]].setState(false);
			}
			nbSelected -- ;
		}
		selected[1] = 0;
		dispOperation();
	}


	public boolean action(Event event, Object obj)
	{
		Object oTarget = event.target;
		if (oTarget instanceof Button)
		{
			Button button = (Button)oTarget;
			if (button == btnMigrate)
			{
				NewGenese();
				bMigration = true;
				repaint();
				bMigration = false;
				return true;
			}
			else if (button == btnGo)
			{
				NewGeneration();
				repaint();
				return true;
			}
			else if (button == btnShowGenome)
			{
				flipShowGenome();
				return true;
			}
		}
		else if (oTarget instanceof Checkbox)
		{
			Checkbox checkbox = (Checkbox)oTarget;
			String label = checkbox.getLabel();
			if (checkbox.getState() == true) {
			   	addSelected(label);
		    } else if (checkbox.getState() == false) {
				delSelected(label);
			}
			return true;
		}
		else if (oTarget instanceof List)
		{
			List list = (List)oTarget;
			if (list == lstMutation)
			{
				MaxSeverity = list.getSelectedIndex();
				dispMutation();
			} else if (list == lstTranscription) {
				TypeTranscription = list.getSelectedIndex();
				dispTranscription();
			} else if (list == lstBackColor) {
				backGround = fixColor(list.getSelectedIndex());
				repaint();
			} else if (list == lstForeColor) {
				foreGround = fixColor(list.getSelectedIndex());
				repaint();
			}
			return true;
		}
		return false;
	}
}

// *************************************************
//
//  CLASS morph
//
// *************************************************


class morph
{
	public static final int NBVAR = 8;
	private final int OptimumOrder = 7;
	private int nDirection = 0;
	private int nOrder;

	private int MaxY;
	private Dimension xy;

	public int dx[], dy[];
	private Vector FromPt, ToPt;
	public genome Genome;
	private int gene[];
	private boolean computed;
	private int transcription;


	public morph(genome Gen, int Transcript)
	{
		Genome = Gen;
		gene = Genome.chromosome;
		dx = new int[NBVAR];
		dy = new int[NBVAR];


		FromPt = new Vector();
		ToPt = new Vector();
		MaxY = 0;
		transcription = Transcript;
		computed = false;
	}

	public morph(String S, int Transcript)
	{
		Genome = new genome(S);
		gene = Genome.chromosome;
		dx = new int[NBVAR];
		dy = new int[NBVAR];


		FromPt = new Vector();
		ToPt = new Vector();
		MaxY = 0;
		transcription = Transcript;
		computed = false;
	}

	public boolean Isvalid()
	{
		return Genome.Isvalid();
	}

	public void mutate(int severity, Random r)
	{
		Genome.mutate(severity,r);
		computed = false;
	}

	public void reTranscript(int Transcript)
	{
		computed = false;
		transcription = Transcript;
		transcript();
	}

	public String toString()
	{
		return Genome.toString();
	}

	private void transcript()
	{
		dx[0] = -gene[1] / 4;
		dx[1] = -gene[0] / 4;
		dx[2] = gene[3] / 2;
		dx[3] = gene[0] / 2;
		dx[4] = gene[1] / 2;
		dx[5] = gene[2] / 2;
		dx[6] = -dx[2] / 2;
		dx[7] = -dx[5] / 2;

		dy[0] = (gene[5])/2;
		dy[1] = (gene[4]);
		dy[2] = (gene[3]);
		dy[3] = -(gene[4]);
		dy[4] = -(gene[5]);
		dy[5] = (gene[6]);
		dy[6] = (gene[0]);
		dy[7] = -dy[5];

		if (transcription == 1) {
			gene[8] = OptimumOrder;
		} else {
			gene[8] = (gene[8] < 0) ? - gene[8] : gene[8];
			gene[8] = (gene[8] < 3) ?  3 : gene[8];
		}

		nOrder = gene[8];

		tree (0, 0, nOrder, nDirection);

	}

	public void phenotype(Graphics g, int x, int y)
	{
		if (computed == false) {
			transcript();
		}
		Dimension Pt1, Pt2;
		for (int i = 0; i < FromPt.size(); i ++)
		{
			Pt1 = (Dimension)FromPt.elementAt(i);
			Pt2 = (Dimension)ToPt.elementAt(i);
			g.drawLine (x + Pt1.width, y - MaxY + Pt1.height,
				        x + Pt2.width, y - MaxY + Pt2.height);
			g.drawLine (x  - Pt1.width, y - MaxY + Pt1.height,
				        x  - Pt2.width, y - MaxY + Pt2.height);
		}
	}

	private void PushGene (int x1, int y1, int x2, int y2)
	{
		if (y1 > MaxY ) {
			MaxY = y1;
		} else if (y2 > MaxY) {
			MaxY = y2;
		}
		FromPt.addElement(new Dimension(x1, y1));
		ToPt.addElement(new Dimension(x2, y2));
	}

	private void tree (int x, int y, int order, int dir)
	{
		int Xnew, Ynew;
		if (dir < 0) {
			dir += NBVAR;
		} else if (dir >= NBVAR) {
			dir -= NBVAR;
		}
		Xnew = x + order * dx[dir];
		Ynew = y + order * dy[dir];
		if ( Ynew > 100 ) Ynew = 100;
		PushGene(x, y, Xnew, Ynew);
		if (order > 0)
		{
			tree (Xnew, Ynew, order - 1, dir - 1);
			tree (Xnew, Ynew, order - 1, dir + 1);
		}
		computed = true;
	}
}

// *************************************************
//
//  CLASS genome
//
// *************************************************


class genome
{

	static final int NBGENE = 9;
	static final int MAXLEN = 7;
	public int chromosome[];
	private int RS;
	private boolean valid;


	public genome(Random r)
	{
		chromosome = new int[NBGENE];
		GetVal(r);
		valid = true;
	}

	public genome(int c[])
	{
		chromosome = new int[NBGENE];
		for (int i = 0; i < NBGENE; i++)
		{
			chromosome[i] = c[i];
		}
		valid = true;
	}

	public genome(String S)
	{
		Random rr = new Random();
		chromosome = new int[NBGENE];

		valid = S.trim().length() == NBGENE;
		if (valid)
		{	char c[] = new char[NBGENE];
			c = S.toUpperCase().trim().toCharArray();
			for (int i = 0;  i < NBGENE-1 ; i++) {
				chromosome[i] = ((int)c[i] - 71) % MAXLEN;}
			chromosome[NBGENE-1] = ((int)c[NBGENE-1] - 71) % (MAXLEN+1);
			if (chromosome[NBGENE-1] < 3)		chromosome[NBGENE-1] = 3;
		} else {
			GetVal(rr);
		}
	}

	public boolean Isvalid()
	{
		return valid;
	}

	public void mutate(int maxSeverity, Random r)
	{
		if (maxSeverity > 0 )
		{
			int p = r.nextInt() % (NBGENE);
			p = (p < 0) ? -p : p;

			int severity = r.nextInt(); // % (maxSeverity + 1);
			// severity = severity % maxSeverity + 1;
			int mute = severity % maxSeverity + 1;;

			chromosome[p] += mute;
			if (p<(NBGENE-1)) {
				chromosome[p] %= (MAXLEN );
			} else 	{
				chromosome[p] %= (MAXLEN + 1);
			}

		}
	}

	private void GetVal(Random r)
	{
		for (int i = 0; i < NBGENE-1; i++)
		{
			chromosome[i] = r.nextInt() % MAXLEN;
		}
		chromosome[NBGENE-1] = r.nextInt() % (MAXLEN+1);
	}

	public String toString()
	{
		String S0 ;
//		String S1, S2;
		char c[];
		c = new char[NBGENE];
		for (int i=0; i < NBGENE; i++)
		{
			c[i] = ((char)(chromosome[i]+71));
		}
		S0 = new String(" "+c);
		return S0;
	}

}

// *************************************************
//
//  CLASS zygote
//
// *************************************************



class zygote
{
	private genome male, female;

	public zygote (genome mG, genome fG)
	{
		male =  new genome(mG.chromosome);
		female = new genome(fG.chromosome);
	}

	public genome getMale()
	{
		return male;
	}

	public genome getFemale()
	{
		return female;
	}

	public genome getChild(Random r)
	{
		int p;
		p = r.nextInt();
		if ( (p) < 0) {
			return female;
		} else {
			return male;
		}

	}

	public void crossing_over(Random r, int nCross)
	{
		int lenGenome = male.NBGENE;
		int i, temp, p, k;
		// nCross x crossing-over at p
		for (k = 0; k < nCross; k++)
		{
			p = r.nextInt() % lenGenome;
			p = p < 0 ? -p : p ;
			for ( i = p; i < lenGenome; i++)
			{
				temp = male.chromosome[i];
				male.chromosome[i] = female.chromosome[i];
				female.chromosome[i] = temp;
			}
		}
	}
}
